"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments)).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
    return { next: verb(0), "throw": verb(1), "return": verb(2) };
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [0, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var mongodb = require("mongodb");
var mongoose = require("mongoose");
var Player = require("./player");
var User = require("./user");
var GameRecord = require("./gameRecord");
var JsonDiff = require("../jsonDiff");
;
// gifts: [{
// 	id: Number,
// 	amount: Number,
// 	_id: false,		
// }],
exports.Schema = new mongoose.Schema({
    number: Number,
    mode: { type: Number, default: 1 },
    index: { type: Number, default: 1 },
    password: { type: String, default: "" },
    owner: { type: mongoose.Schema.Types.ObjectId, ref: "Player" },
    isStart: { type: Boolean, default: false },
    days: { type: Number, default: 1 },
    isMorning: { type: Boolean, default: false },
    isMorningSpeak: { type: Boolean, default: false },
    enableWithdrawn: { type: Boolean, default: true },
    lastExilePlayers: [{ type: mongoose.Schema.Types.ObjectId, ref: "Player" }],
    speakLoopTimes: { type: Number, default: 0 },
    isSpeakAtRight: Boolean,
    players: [Player.Schema],
    viewers: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
    timeoutAt: Number,
    roundId: String,
    dayRounds: [String],
    speakType: { type: Number, default: 0 },
    deadSpeakPlayers: [{ type: mongoose.Schema.Types.ObjectId, ref: "Player" }],
    lastDeadPlayer: { type: mongoose.Schema.Types.ObjectId, ref: "Player" },
    record: { type: mongoose.Schema.Types.ObjectId, ref: "GameRecord" },
    _syncVersion: { type: Number, default: 0 },
    // 直播
    isLive: { type: Boolean, default: false },
    seatPrices: [Number],
    title: String,
    coverUrl: String,
    nextSpeakPlayer: { type: mongoose.Schema.Types.ObjectId, ref: "Player", default: null },
    // isFoolSpeaking: { type: Boolean, default: false }
    isFoolSpeaking: Boolean,
    deadPlayerArrEveryDay: [Number],
});
exports.Model = mongoose.model("Room", exports.Schema);
var isGuarded = false;
var isJoin = false;
var rounds = [
    {
        id: "游戏开始",
        time: 5,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var _a, getRandomRoles, randomRoles, i, player, roleIndex, i, player, i, player;
                return __generator(this, function (_b) {
                    switch (_b.label) {
                        case 0:
                            room.isStart = true;
                            room.days = 0;
                            // room.deadPlayers = [];
                            room.players.forEach(function (p) {
                                if (!!p) {
                                    p.isReady = false;
                                    // p.selectablePlayers = [];
                                    // p.selectedPlayers = [];
                                    // p.roleFlags = [];
                                    // p.flags = [];
                                    p.role = p.user.role ? p.user.role : "";
                                }
                            });
                            _a = room;
                            return [4 /*yield*/, GameRecord.create(room)];
                        case 1:
                            _a.record = (_b.sent())._id;
                            getRandomRoles = function (count) {
                                var fillRoles = ["村民", "村民", "村民", "村民", "侍卫", "预言家", "猎人", "女巫", "狼人", "狼人", "狼人", "刺客"];
                                var randomRoles = [];
                                while (fillRoles.length > 0) {
                                    var randomIndex = Math.floor(Math.random() * fillRoles.length);
                                    randomRoles.push(fillRoles[randomIndex]);
                                    fillRoles.splice(randomIndex, 1);
                                }
                                return randomRoles;
                            };
                            randomRoles = getRandomRoles(room.players.length);
                            console.warn("角色分配：" + randomRoles);
                            console.warn("角色分配：" + randomRoles);
                            console.warn("角色分配：" + randomRoles);
                            for (i = 0; i < room.players.length; i++) {
                                player = room.players[i];
                                if (!!player && player.role) {
                                    roleIndex = randomRoles.indexOf(player.role);
                                    if (roleIndex >= 0)
                                        randomRoles.splice(roleIndex, 1);
                                    else
                                        player.role = "";
                                }
                            }
                            for (i = 0; i < room.players.length; i++) {
                                player = room.players[i];
                                if (!player || player.role)
                                    continue;
                                player.role = randomRoles[0];
                                randomRoles.splice(0, 1);
                            }
                            for (i = 0; i < room.players.length; i++) {
                                player = room.players[i];
                                if (!!player && player.role) {
                                    player.camp = player.role == "狼人" || player.role == "刺客" ? "狼人" : "好人";
                                }
                            }
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) { return "天黑"; },
    },
    {
        id: "天黑",
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            room.isMorning = false;
                            room.deadPlayerArrEveryDay = []; //每天晚上死亡的人数组 初始化
                            room.days++;
                            room.dayRounds = [];
                            return [4 /*yield*/, pushRoomEvent(app, room, "天黑了")];
                        case 1:
                            _a.sent();
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "天黑", { days: room.days })];
                        case 2:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (hasRole(room, "侍卫")) {
                return "守卫行动";
            }
            else {
                return "狼人行动";
            }
        },
    },
    {
        id: "丘比特行动",
        time: 15,
        selectConfig: {
            count: 2,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.role == "丘比特"; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var targetNumbers, i, p, wolfCount, _loop_1, j;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            targetNumbers = [];
                            for (i = 0; i < room.players.length; i++) {
                                p = room.players[i];
                                if (!!p && p.deadInfo.state == 0 && p.role == "丘比特") {
                                    if (p.selectedPlayers.indexOf(null) >= 0) {
                                        continue;
                                    }
                                    wolfCount = 0;
                                    _loop_1 = function (j) {
                                        var p2 = room.players[j];
                                        if (!!p2 && p.selectedPlayers.find(function (pid) { return !!pid && !!p2 && pid.equals(p2._id); })) {
                                            p2.isLover = true;
                                            targetNumbers.push(j + 1);
                                            if (p2.role == "狼人") {
                                                wolfCount++;
                                            }
                                        }
                                    };
                                    for (j = 0; j < room.players.length; j++) {
                                        _loop_1(j);
                                    }
                                    if (wolfCount == 0) {
                                    }
                                    else if (wolfCount == p.selectedPlayers.length) {
                                    }
                                    else {
                                        // 戀人
                                        p.camp = "恋人";
                                        room.players.forEach(function (p2) {
                                            if (!!p2 && p2.isLover) {
                                                p2.camp = "恋人";
                                            }
                                        });
                                    }
                                }
                            }
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "丘比特行动", { targetNumbers: targetNumbers })];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) { return "情侣互认身份"; },
    },
    {
        id: "情侣互认身份",
        time: 5,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) {
            if (hasRole(room, "守卫")) {
                return "守卫行动";
            }
            else {
                return "狼人行动";
            }
        },
    },
    {
        id: "守卫行动",
        time: 15,
        selectConfig: {
            count: 1,
            // 侍卫可以救 前一天被放逐的人
            selectableFilter: function (player, room) { return player.deadInfo.state == 5 && player.deadInfo.day == room.days - 1; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.role == "侍卫" && player.roleFlags.indexOf("saved") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, po, s_1, savedPerson_1, targetNumber;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "侍卫"; }));
                            if (!target)
                                return [3 /*break*/, 3];
                            target.flags.push("save");
                            po = room.players.find(function (p) { return !!p && p.role == "侍卫"; });
                            po.roleFlags.push("saved");
                            s_1 = po.selectedPlayers[0];
                            if (!!!s_1)
                                return [3 /*break*/, 3];
                            isGuarded = true;
                            savedPerson_1 = room.players.find(function (p) { return !!p && p._id.equals(s_1); });
                            savedPerson_1.deadInfo.state = 0;
                            // 守卫行动了之后     刺客没有刺杀的技能   女巫没有技能   猎人没有技能  预言家没有技能   
                            switch (savedPerson_1.role.trim()) {
                                case "刺客":
                                    // savedPerson.roleFlags.push("assassed");
                                    savedPerson_1.roleFlags.push("callback");
                                    break;
                                case "女巫":
                                    // savedPerson.roleFlags.push("cure");
                                    // savedPerson.roleFlags.push("posion");
                                    savedPerson_1.roleFlags.push("callback");
                                    break;
                                case "猎人":
                                    // savedPerson.roleFlags.push("gun");
                                    savedPerson_1.roleFlags.push("callback");
                                    break;
                                case "预言家":
                                    // savedPerson.roleFlags.push("seed");
                                    savedPerson_1.roleFlags.push("callback");
                                    break;
                            }
                            return [4 /*yield*/, sync(app, room)];
                        case 1:
                            room = _a.sent();
                            return [4 /*yield*/, pushRoomEvent(app, room, "侍卫救人", {
                                    'number': function (p) { return room.players.indexOf(savedPerson_1); }
                                })];
                        case 2:
                            _a.sent();
                            _a.label = 3;
                        case 3:
                            targetNumber = room.players.findIndex(function (p) { return !!target && !!p && p._id.equals(target._id); }) + 1;
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "侍卫行动", { targetNumber: targetNumber })];
                        case 4:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function () {
            if (isGuarded) {
                isGuarded = false;
                return "玩家复活";
            }
            return "狼人行动";
        }
    },
    {
        id: "玩家复活",
        time: 5,
        onStart: function (any, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (any, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function () { return "狼人行动"; }
    },
    {
        id: "狼人行动",
        time: 25,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && (player.role == "狼人" || player.role == "刺客"); },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, targetNumber;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && (p.role == "狼人" || p.role == "刺客"); }));
                            if (target) {
                                target.flags.push("kill");
                            }
                            targetNumber = room.players.findIndex(function (p) { return !!target && !!p && p._id.equals(target._id); }) + 1;
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "狼人行动", { targetNumber: targetNumber })];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (hasRole(room, "刺客")) {
                return "刺客行动";
            }
        },
    },
    {
        id: "刺客行动",
        time: 15,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.role == "刺客" && player.roleFlags.indexOf("assassed") == -1 && player.roleFlags.indexOf("callback") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, po, s_2, assassPerson_1, targetNumber;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "刺客"; }));
                            if (!target)
                                return [3 /*break*/, 2];
                            target.flags.push("assass");
                            po = room.players.find(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "刺客"; });
                            po.roleFlags.push("assassed");
                            s_2 = po.selectedPlayers[0];
                            if (!!!s_2)
                                return [3 /*break*/, 2];
                            assassPerson_1 = room.players.find(function (p) { return !!p && p._id.equals(s_2); });
                            // savedPerson.deadInfo.state == 0;
                            return [4 /*yield*/, pushRoomEvent(app, room, "刺客刺杀", {
                                    'number': function (p) { return room.players.indexOf(assassPerson_1); }
                                })];
                        case 1:
                            // savedPerson.deadInfo.state == 0;
                            _a.sent();
                            _a.label = 2;
                        case 2:
                            targetNumber = room.players.findIndex(function (p) { return !!target && !!p && p._id.equals(target._id); }) + 1;
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "刺客行动", { targetNumber: targetNumber })];
                        case 3:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function () { return "预言家行动"; },
    },
    {
        id: "预言家行动",
        time: 10,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0 && !player.isVerified; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.role == "预言家" && player.flags.indexOf("assass") == -1 && player.roleFlags.indexOf("seed") == -1 && player.roleFlags.indexOf("callback") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, targetNumber;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "预言家"; }));
                            if (!target)
                                return [3 /*break*/, 2];
                            target.isVerified = true;
                            return [4 /*yield*/, pushRoomEvent(app, room, "验人结果", { player: target })];
                        case 1:
                            _a.sent();
                            _a.label = 2;
                        case 2:
                            targetNumber = room.players.findIndex(function (p) { return !!target && !!p && p._id.equals(target._id); }) + 1;
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "预言家行动", { targetNumber: targetNumber })];
                        case 3:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (hasRole(room, "女巫")) {
                return "女巫行动";
            }
            else {
                return "天亮";
            }
        },
    },
    {
        id: "女巫行动",
        time: 10,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0 && player.flags.indexOf("kill") >= 0; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.role == "女巫" && player.roleFlags.indexOf("cure") == -1 && player.flags.indexOf("assass") == -1 && player.roleFlags.indexOf("callback") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, i, p;
                return __generator(this, function (_a) {
                    target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "女巫"; }));
                    if (target) {
                        target.flags.push("cure");
                        for (i = 0; i < room.players.length; i++) {
                            p = room.players[i];
                            if (!!p && p.role == "女巫") {
                                p.roleFlags.push("cure"); // 記錄已用藥
                            }
                        }
                    }
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function () { return "女巫行动-2"; },
    },
    {
        id: "女巫行动-2",
        time: 10,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) {
                return player.deadInfo.state == 0 &&
                    player.role == "女巫" &&
                    player.roleFlags.indexOf("poison") == -1 &&
                    player.flags.indexOf("assass") == -1 &&
                    player.roleFlags.indexOf("callback") == -1 &&
                    !room.players.find(function (p) { return !!p && p.flags.indexOf("cure") >= 0; }); // 這回合沒有人被救
            },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, i, p, targetNumber, flag, i, p;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.role == "女巫"; }));
                            if (target) {
                                target.flags.push("poison");
                                for (i = 0; i < room.players.length; i++) {
                                    p = room.players[i];
                                    if (!!p && p.role == "女巫") {
                                        p.roleFlags.push("poison"); // 記錄已用毒
                                    }
                                }
                            }
                            targetNumber = 0;
                            flag = "";
                            for (i = 0; i < room.players.length; i++) {
                                p = room.players[i];
                                if (p) {
                                    if (p.flags.indexOf("poison") >= 0) {
                                        targetNumber = i + 1;
                                        flag = "poison";
                                    }
                                    else if (p.flags.indexOf("cure") >= 0) {
                                        targetNumber = i + 1;
                                        flag = "cure";
                                    }
                                }
                            }
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "女巫行动", { targetNumber: targetNumber, flag: flag })];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function () { return "天亮"; },
    },
    {
        id: "天亮",
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var assassPerson;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            room.isMorning = true;
                            room.isMorningSpeak = false;
                            room.isSpeakAtRight = true;
                            assassPerson = room.players.find(function (p) { return !!p && p.flags.indexOf("assass") != -1; });
                            if (assassPerson) {
                                assassPerson.flags.splice(assassPerson.flags.indexOf("assass"), 1);
                            }
                            return [4 /*yield*/, pushRoomEvent(app, room, "天亮了")];
                        case 1:
                            _a.sent();
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "天亮", { days: room.days })];
                        case 2:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) { return room.days == 1 ? "参选警长" : "玩家死亡"; },
    },
    {
        id: "参选警长",
        time: 10,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    room.players.forEach(function (p) {
                        if (!!p) {
                            p.selectablePlayers = [p._id];
                            p.selectedPlayers = [null];
                        }
                    });
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var leaders, leader;
                return __generator(this, function (_a) {
                    room.players.forEach(function (p) {
                        if (!!p && !!p.selectedPlayers[0]) {
                            p.leaderState = 1;
                        }
                    });
                    leaders = room.players.filter(function (p) { return !!p && p.leaderState == 1; });
                    if (leaders.length == 1) {
                        leader = leaders[0];
                        leader.leaderState = 3;
                    }
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) {
            if (!!room.players.find(function (p) { return !!p && p.leaderState == 3; })) {
                return "获得警徽";
            }
            // 0: 沒上警, 1: 上警, 2: 退水, 3: 當選
            if (!room.players.find(function (p) { return !!p && p.leaderState == 0; }) ||
                !room.players.find(function (p) { return !!p && p.leaderState == 1; })) {
                return "获得警徽";
            }
            return room.mode == 1 ? "警长投票" : "竞选警长";
        },
    },
    {
        id: "竞选警长",
        onInit: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    room = onSpeakRoundInit(room);
                    return [2 /*return*/, room];
                });
            });
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var votedPids, votePeople, elseVotePeople, elseVotePids, _loop_2, i, i, leaders, leader;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            console.log("=================speakLoopTimes==========================" + room.speakLoopTimes);
                            votedPids = room.players.filter(function (p) { return !!p && p.leaderState == 1; }).map(function (p2) { return !!p2 && p2._id; });
                            votePeople = room.players.filter(function (p) { return !!p && p.leaderState == 1; });
                            elseVotePeople = room.players.filter(function (p) { return !!p && p.leaderState != 1; });
                            elseVotePids = room.players.filter(function (p) { return !!p && p.leaderState != 1; }).map(function (p2) { return !!p2 && p2._id; });
                            if (!(room.speakLoopTimes < 2))
                                return [3 /*break*/, 5];
                            _loop_2 = function (i) {
                                var p;
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0:
                                            p = votePeople[i];
                                            if (!(!!p && p.leaderState == 1 && !!room.lastExilePlayers.find(function (lep) { return !!p && lep.equals(p._id); })))
                                                return [3 /*break*/, 2];
                                            return [4 /*yield*/, setPlayerSpeak(app, room, votedPids, i, 60, 1)];
                                        case 1:
                                            room = _a.sent();
                                            _a.label = 2;
                                        case 2: return [2 /*return*/];
                                    }
                                });
                            };
                            i = 0;
                            _a.label = 1;
                        case 1:
                            if (!(i < votePeople.length))
                                return [3 /*break*/, 4];
                            return [5 /*yield**/, _loop_2(i)];
                        case 2:
                            _a.sent();
                            _a.label = 3;
                        case 3:
                            i++;
                            return [3 /*break*/, 1];
                        case 4: return [3 /*break*/, 9];
                        case 5:
                            if (!(room.speakLoopTimes == 2))
                                return [3 /*break*/, 9];
                            i = 0;
                            _a.label = 6;
                        case 6:
                            if (!(i < elseVotePeople.length))
                                return [3 /*break*/, 9];
                            return [4 /*yield*/, setPlayerSpeak(app, room, elseVotePids, i, 60, 1)];
                        case 7:
                            // let p = elseVotePeople[i];
                            room = _a.sent();
                            _a.label = 8;
                        case 8:
                            i++;
                            return [3 /*break*/, 6];
                        case 9:
                            leaders = room.players.filter(function (p) { return !!p && p.leaderState == 1; });
                            if (leaders.length == 1) {
                                leader = leaders[0];
                                leader.leaderState = 3;
                            }
                            room = onSpeakRoundEnd(room);
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (!!room.players.find(function (p) { return !!p && p.leaderState == 3; })) {
                return "获得警徽";
            }
            if (!room.players.find(function (p) { return !!p && p.leaderState == 0; }) ||
                !room.players.find(function (p) { return !!p && p.leaderState == 1; })) {
                return "获得警徽";
            }
            return "警长投票";
        },
    },
    {
        id: "警长投票",
        time: 15,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.leaderState == 1; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.leaderState == 0; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    isJoin = true;
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, selectedId_1, maxSelectPlayers, losePoliceBadges, i, player;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            if (!(room.mode == 1))
                                return [3 /*break*/, 2];
                            target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && (room.speakLoopTimes == 1 || !room.lastExilePlayers.find(function (lep) { return lep.equals(p._id); })); }), true);
                            if (!!target) {
                                target.leaderState = 3;
                            }
                            return [4 /*yield*/, pushVoteResult(app, room, target ? target._id.toString() : "", 1)];
                        case 1:
                            _a.sent();
                            return [3 /*break*/, 4];
                        case 2:
                            if (!(room.mode == 2))
                                return [3 /*break*/, 4];
                            selectedId_1 = "";
                            maxSelectPlayers = getMaxSelectPlayers(room.players.filter(function (p) { return !!p && (room.speakLoopTimes == 1 || !room.lastExilePlayers.find(function (lep) { return lep.equals(p._id); })); }));
                            room.lastExilePlayers = maxSelectPlayers;
                            losePoliceBadges = room.players.filter(function (p) { return !!p && p.leaderState == 1 && room.lastExilePlayers.indexOf(p._id) == -1; });
                            for (i = 0; i < losePoliceBadges.length; i++) {
                                losePoliceBadges[i].leaderState = 0;
                            }
                            if (maxSelectPlayers.length == 1) {
                                selectedId_1 = maxSelectPlayers[0].toString();
                                player = room.players.find(function (p) { return !!p && p._id.toString() == selectedId_1; });
                                player.leaderState = 3;
                            }
                            return [4 /*yield*/, pushVoteResult(app, room, selectedId_1, 1)];
                        case 3:
                            _a.sent();
                            _a.label = 4;
                        case 4: return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            return "投票结果显示";
        },
    },
    {
        id: "获得警徽",
        time: 5,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function () { return "玩家死亡"; },
    },
    {
        id: "警长选择发言顺序",
        time: 5,
        //???  判断是否有狼人自爆有什么用？
        isSkip: function (room) { return hasExposure(room); },
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return false; },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && player.leaderState == 3 && player.roleFlags.indexOf("exileFool") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var i, player, leaderIndex, deadLen, leftPlayers, rightPlayers;
                return __generator(this, function (_a) {
                    for (i = 0; i < room.players.length; i++) {
                        player = room.players[i];
                        if (!!player && player.selectedPlayers.length > 0) {
                            leaderIndex = room.players.findIndex(function (p) { return !!p && p.leaderState == 3 && p.deadInfo.state == 0; });
                            deadLen = room.deadPlayerArrEveryDay.length;
                            if (leaderIndex == -1) {
                                continue;
                            }
                            else if (leaderIndex > -1 && deadLen == 1) {
                                leaderIndex = room.deadPlayerArrEveryDay[0];
                            }
                            else if (leaderIndex > -1 && deadLen >= 1) {
                            }
                            leftPlayers = relistPlayers(room, leaderIndex - 1, false, function (p) { return !!p && p.deadInfo.state == 0; });
                            rightPlayers = relistPlayers(room, leaderIndex + 1, true, function (p) { return !!p && p.deadInfo.state == 0; });
                            player.selectablePlayers = [leftPlayers[0]._id, rightPlayers[0]._id];
                        }
                    }
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var target, leaderIndex, targetIndex, leftIndex;
                return __generator(this, function (_a) {
                    target = getOneTarget(app, room, room.players.filter(function (p) { return !!p && p.deadInfo.state == 0 && p.leaderState == 3; }));
                    if (target) {
                        leaderIndex = room.players.findIndex(function (p) { return !!p && p.deadInfo.state == 0 && p.leaderState == 3; });
                        //死一个，死上死下
                        if (room.deadPlayerArrEveryDay.length == 1) {
                            leaderIndex = room.deadPlayerArrEveryDay[0];
                        }
                        targetIndex = room.players.findIndex(function (p) { return !!p && !!target && p._id.equals(target._id); });
                        leftIndex = (leaderIndex - 1 + room.players.length) % room.players.length;
                        if (targetIndex == leftIndex) {
                            room.isSpeakAtRight = false;
                        }
                    }
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) { return room.isMorningSpeak ? "天黑" : "日常发言"; },
    },
    {
        id: "日常发言",
        isSkip: function (room) { return hasExposure(room); },
        onInit: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    room = onSpeakRoundInit(room);
                    return [2 /*return*/, room];
                });
            });
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var _loop_3, loopTimes;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            //传统模式第一天 日常发言两次
                            // 标准模式  公投票数 一样  玩家发言一次
                            console.log("=============room.isMorningSpeak)" + room.isMorningSpeak);
                            console.log("=============room.room.mode == 1 && room.days == 1&&room.isMorningSpeak)" + (room.mode == 1 && room.days == 1 && room.isMorningSpeak));
                            _loop_3 = function (loopTimes) {
                                var startIndex, speakAtRight, lastDeadPlayer_1, leaderIndex, leaderIndex, deadLen, players, pids, i, foolP;
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0:
                                            startIndex = 0;
                                            speakAtRight = true;
                                            //传统模式
                                            if (room.mode == 1) {
                                                lastDeadPlayer_1 = room.players.find(function (p) { return !!p && !!room.lastDeadPlayer && p._id.equals(room.lastDeadPlayer); });
                                                if (!!lastDeadPlayer_1 && lastDeadPlayer_1.deadInfo.day == room.days) {
                                                    startIndex = room.players.findIndex(function (p) { return !!p && !!lastDeadPlayer_1 && p._id.equals(lastDeadPlayer_1._id); }) + 1;
                                                }
                                                else {
                                                    leaderIndex = room.players.findIndex(function (p) { return !!p && p.leaderState == 3; });
                                                    if (leaderIndex >= 0) {
                                                        startIndex = leaderIndex;
                                                    }
                                                }
                                            }
                                            else if (room.mode == 2) {
                                                leaderIndex = room.players.findIndex(function (p) { return !!p && p.leaderState == 3 && p.deadInfo.state == 0; });
                                                deadLen = room.deadPlayerArrEveryDay.length;
                                                //没有警长  死一个或者多个 ，以死的序号大的玩家  为基准发言	
                                                if (leaderIndex == -1 && deadLen > 0) {
                                                    leaderIndex = room.deadPlayerArrEveryDay[deadLen - 1];
                                                }
                                                else if (leaderIndex > -1 && deadLen == 1) {
                                                    leaderIndex = room.deadPlayerArrEveryDay[0];
                                                }
                                                else if (leaderIndex > -1 && deadLen >= 1) {
                                                }
                                                if (leaderIndex >= 0) {
                                                    startIndex = leaderIndex + (room.isSpeakAtRight ? 1 : -1);
                                                    speakAtRight = room.isSpeakAtRight;
                                                }
                                            }
                                            players = [];
                                            console.log("==========日常发言======room.speakLoopTimes=================" + room.speakLoopTimes);
                                            if (room.speakLoopTimes < 2)
                                                players = relistPlayers(room, startIndex, speakAtRight, function (p) { return !!p && p.roleFlags.indexOf("exileFool") == -1 && p.deadInfo.state == 0 && !!room.lastExilePlayers.find(function (lep) { return !!p && lep.equals(p._id); }); });
                                            else
                                                players = relistPlayers(room, startIndex, speakAtRight, function (p) { return !!p && p.roleFlags.indexOf("exileFool") == -1 && p.deadInfo.state == 0 && !room.lastExilePlayers.find(function (lep) { return !!p && lep.equals(p._id); }); });
                                            pids = players.map(function (p) { return p._id; });
                                            i = 0;
                                            _a.label = 1;
                                        case 1:
                                            if (!(i < pids.length))
                                                return [3 /*break*/, 6];
                                            return [4 /*yield*/, setPlayerSpeak(app, room, pids, i, 60, 1)];
                                        case 2:
                                            room = _a.sent();
                                            foolP = room.players.find(function (p) { return !!p && p.roleFlags.indexOf("exileFool") >= 0 && p.deadInfo.state == 0; });
                                            if (!foolP)
                                                return [3 /*break*/, 5];
                                            if (!room.isFoolSpeaking)
                                                return [3 /*break*/, 5];
                                            console.warn("//白痴插嘴   ...............................。。。。。。。。。。。。。");
                                            room.isFoolSpeaking = false;
                                            return [4 /*yield*/, sync(app, room)];
                                        case 3:
                                            room = _a.sent();
                                            return [4 /*yield*/, setPlayerSpeak(app, room, [foolP._id], 0, 20, 1, true)];
                                        case 4:
                                            room = _a.sent();
                                            _a.label = 5;
                                        case 5:
                                            i++;
                                            return [3 /*break*/, 1];
                                        case 6: return [2 /*return*/];
                                    }
                                });
                            };
                            loopTimes = 0;
                            _a.label = 1;
                        case 1:
                            if (!(loopTimes < ((room.mode == 1 && room.days == 1 && !room.isMorningSpeak) ? 2 : 1)))
                                return [3 /*break*/, 4];
                            return [5 /*yield**/, _loop_3(loopTimes)];
                        case 2:
                            _a.sent();
                            _a.label = 3;
                        case 3:
                            loopTimes++;
                            return [3 /*break*/, 1];
                        case 4:
                            room.isMorningSpeak = true;
                            room = onSpeakRoundEnd(room);
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) { return hasExposure(room) ? "天黑" : "放逐投票"; },
    },
    {
        id: "放逐投票",
        time: 20,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return !!room.lastExilePlayers.find(function (lep) { return lep.equals(player._id); }); },
            selectorFilter: function (player, room) { return player.deadInfo.state == 0 && (room.speakLoopTimes == 1 || !room.lastExilePlayers.find(function (lep) { return lep.equals(player._id); })); },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var selectedId, maxSelectPlayers, targetNumber;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            selectedId = "";
                            maxSelectPlayers = getMaxSelectPlayers(room.players.filter(function (p) { return !!p && (room.speakLoopTimes == 1 || !room.lastExilePlayers.find(function (lep) { return lep.equals(p._id); })); }), room);
                            room.lastExilePlayers = maxSelectPlayers;
                            targetNumber = 0;
                            if (!(maxSelectPlayers.length == 1))
                                return [3 /*break*/, 2];
                            selectedId = maxSelectPlayers[0].toString();
                            return [4 /*yield*/, killPlayer(app, room, maxSelectPlayers[0], 5)];
                        case 1:
                            room = _a.sent();
                            room.speakLoopTimes = 3;
                            targetNumber = room.players.findIndex(function (p) { return !!p && p._id.toString() == selectedId; }) + 1;
                            _a.label = 2;
                        case 2: 
                        //将放逐的投票结果发送给Client
                        return [4 /*yield*/, pushVoteResult(app, room, selectedId, 2)];
                        case 3:
                            //将放逐的投票结果发送给Client
                            _a.sent();
                            if (!(targetNumber > 0))
                                return [3 /*break*/, 5];
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "放逐投票", { targetNumber: targetNumber })];
                        case 4:
                            _a.sent();
                            _a.label = 5;
                        case 5: return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            return "投票结果显示";
        },
    },
    {
        id: "投票结果显示",
        time: 5,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) {
            // if (getWinner(room)) {
            // 	return "游戏结束";
            // }
            if (!!room.players.find(function (p) { return !!p && room.days == 1 && room.isMorningSpeak == false && isJoin; })) {
                isJoin = false;
                return "获得警徽";
            }
            if (room.mode == 2 && room.days == 1 && room.isMorningSpeak == false) {
                var hasSelector_1 = room.speakLoopTimes == 0 ? true : (!!room.players.find(function (p) { return !!p && p.deadInfo.state == 0 && p.leaderState == 0; }));
                if (room.lastExilePlayers.length > 0
                    && hasSelector_1
                    && room.speakLoopTimes < 3) {
                    return "竞选警长";
                }
            }
            console.log("==================room.speakLoopTimes ====================" + room.speakLoopTimes);
            var hasSelector = room.speakLoopTimes == 0 ? true : (room.players.filter(function (p) { return !!p && p.deadInfo.state == 0; }).length > 0);
            if (room.lastExilePlayers.length > 0
                && hasSelector
                && room.speakLoopTimes < 3) {
                return "日常发言";
            }
            return "玩家死亡";
        },
    },
    {
        id: "玩家死亡",
        time: 5,
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var targetNumbers, alivePlayers, sortArr, i, player, hasKill, hasGuard, hasCure, hasPoison, deadPlayers;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            targetNumbers = [];
                            alivePlayers = room.players.filter(function (p) { return !!p && p.deadInfo.state == 0; });
                            sortArr = sortDeadPlayer(alivePlayers);
                            if (!!!sortArr)
                                return [3 /*break*/, 9];
                            console.warn("====sortArr.map(p=>!!p&&room.players.indexOf(p) + 1)=====" + sortArr.map(function (p) { return !!p && room.players.indexOf(p) + 1; }));
                            i = 0;
                            _a.label = 1;
                        case 1:
                            if (!(i < sortArr.length))
                                return [3 /*break*/, 9];
                            player = sortArr[i];
                            if (!player)
                                return [3 /*break*/, 8];
                            hasKill = player.flags.indexOf("kill") >= 0;
                            hasGuard = player.flags.indexOf("guard") >= 0;
                            hasCure = player.flags.indexOf("cure") >= 0;
                            hasPoison = player.flags.indexOf("poison") >= 0;
                            if (!(hasCure && hasGuard))
                                return [3 /*break*/, 3];
                            //4: 同守同救
                            console.warn("===============//4同守同救==========================");
                            return [4 /*yield*/, killPlayer(app, room, player._id, 4)];
                        case 2:
                            room = _a.sent();
                            targetNumbers.push(i + 1);
                            return [3 /*break*/, 7];
                        case 3:
                            if (!(hasKill && !hasCure && !hasGuard))
                                return [3 /*break*/, 5];
                            //1：狼人刀杀
                            console.warn("===============//1：狼人刀杀==========================");
                            return [4 /*yield*/, killPlayer(app, room, player._id, 1)];
                        case 4:
                            room = _a.sent();
                            targetNumbers.push(i + 1);
                            return [3 /*break*/, 7];
                        case 5:
                            if (!hasPoison)
                                return [3 /*break*/, 7];
                            console.warn("===============//2：女巫毒杀==========================");
                            return [4 /*yield*/, killPlayer(app, room, player._id, 2)];
                        case 6:
                            room = _a.sent();
                            targetNumbers.push(i + 1);
                            _a.label = 7;
                        case 7:
                            player.flags = [];
                            _a.label = 8;
                        case 8:
                            i++;
                            return [3 /*break*/, 1];
                        case 9:
                            deadPlayers = alivePlayers.filter(function (p) { return p.deadInfo.state > 0; });
                            return [4 /*yield*/, pushRoomEvent(app, room, "多个玩家死亡", {
                                    'numbers': deadPlayers.map(function (p) { return room.players.indexOf(p) + 1; }),
                                    'states': deadPlayers.map(function (p) { return p.deadInfo.state; }),
                                })];
                        case 10:
                            _a.sent();
                            return [4 /*yield*/, GameRecord.addEvent(room.record, "玩家死亡", { targetNumbers: targetNumbers })];
                        case 11:
                            _a.sent();
                            //玩家死亡   预加载停止	
                            room.nextSpeakPlayer = null;
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (getWinner(room)) {
                return "游戏结束";
            }
            //白痴的局    白痴是警长  并且被放逐状态  那么接下来走移交警徽流程
            //xianfei 
            for (var i = 0; i < room.players.length; i++) {
                var player = room.players[i];
                //giveLeader
                if (!player)
                    continue;
                // if (player.deadInfo.state > 0 && player.deadInfo.day == room.days) {
                // 	// if (player.role == "猎人" && player.roleFlags.indexOf("gun") == -1 && player.deadInfo.state != 2) {
                // 	// 	return "猎人行动";
                // 	// }
                // 	if (player.leaderState == 3) {
                // 		return "移交警徽";
                // 	}
                // }
                //白痴放逐移交警徽
                var giveLearderIndex = player.roleFlags.indexOf("giveLeader");
                if (giveLearderIndex >= 0) {
                    player.roleFlags.splice(giveLearderIndex, 1);
                    return "移交警徽";
                }
            }
            // if (room.mode == 2 && !room.isMorningSpeak && !!room.players.find(p => !!p && p.leaderState == 3 && p.deadInfo.state == 0)) {
            // 	// if (!room.players.find(p => !!p && p.deadInfo.state > 0 && p.deadInfo.day == room.days)) { // 平安夜
            // 	return "警长选择发言顺序";
            // }
            // return getNextRoundIdBeforeDead(room);
            return "发表遗言";
        },
    },
    {
        id: "猎人行动",
        time: 20,
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) { return player.role == "猎人" && player.roleFlags.indexOf("callback") == -1; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    //猎人翻牌带人，则猎人没有遗言
                    room.deadSpeakPlayers = room.deadSpeakPlayers.filter(function (pid) {
                        var player = room.players.find(function (p) { return !!p && p._id.equals(pid); });
                        return player.role != "猎人";
                    });
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var actionNumber, targetNumber, i, player, j, s;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            actionNumber = 0;
                            targetNumber = 0;
                            i = 0;
                            _a.label = 1;
                        case 1:
                            if (!(i < room.players.length))
                                return [3 /*break*/, 6];
                            player = room.players[i];
                            if (!(!!player && player.role == "猎人"))
                                return [3 /*break*/, 5];
                            player.roleFlags.push("gun");
                            actionNumber = i + 1;
                            j = 0;
                            _a.label = 2;
                        case 2:
                            if (!(j < player.selectedPlayers.length))
                                return [3 /*break*/, 5];
                            s = player.selectedPlayers[j];
                            if (!!!s)
                                return [3 /*break*/, 4];
                            return [4 /*yield*/, killPlayer(app, room, s, 3)];
                        case 3:
                            room = _a.sent();
                            targetNumber = j + 1;
                            _a.label = 4;
                        case 4:
                            j++;
                            return [3 /*break*/, 2];
                        case 5:
                            i++;
                            return [3 /*break*/, 1];
                        case 6: return [4 /*yield*/, GameRecord.addEvent(room.record, "猎人行动", { actionNumber: actionNumber, targetNumber: targetNumber })];
                        case 7:
                            _a.sent();
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) {
            if (getWinner(room)) {
                return "游戏结束";
            }
            // return getNextRoundIdBeforeDead(room);
            // return "发表遗言";
            return "玩家死亡";
        },
    },
    {
        id: "发表遗言",
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var deadSayArr, i, p1, j, p2, speckPids, i;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            console.warn("============进入发表遗言环节==发表遗言玩家的人数=======没有筛选===========" + room.deadSpeakPlayers.length);
                            deadSayArr = [];
                            // 给予  room   去  deap arr去查找
                            for (i = 0; i < room.players.length; i++) {
                                p1 = room.players[i];
                                for (j = 0; j < room.deadSpeakPlayers.length; j++) {
                                    p2 = room.deadSpeakPlayers[j];
                                    if (!!p1 && p1._id.equals(p2)) {
                                        deadSayArr.push(p2);
                                    }
                                }
                            }
                            speckPids = deadSayArr.filter(function (pid) {
                                var player = room.players.find(function (p) { return !!p && p._id.equals(pid); });
                                //第二天开始   夜晚死的玩家【不是被公投】  没有遗言
                                if (room.mode == 2 && room.days != 1 && (player).deadInfo.state != 5 && (player).deadInfo.state != 3) {
                                    return false;
                                }
                                //当玩家被女巫毒死 没有遗言
                                // if (((player) as Player.Document).deadInfo.state == 2) {
                                // 	return false;
                                // }
                                return true;
                            });
                            // let speckPids = room.deadSpeakPlayers;
                            // speckPids = uniqueArr(speckPids)
                            console.warn("=============发表遗言环节=================进入发表遗言环节==发表遗言玩家的人数=======筛选过之后=============" + speckPids.length + "=========xxxxxdeadSpeakPlayers=====" + room.deadSpeakPlayers);
                            i = 0;
                            _a.label = 1;
                        case 1:
                            if (!(i < speckPids.length))
                                return [3 /*break*/, 4];
                            return [4 /*yield*/, setPlayerSpeak(app, room, speckPids, i, 60, 2)];
                        case 2:
                            room = _a.sent(); // 发表遗言的方法
                            _a.label = 3;
                        case 3:
                            i++;
                            return [3 /*break*/, 1];
                        case 4:
                            room.deadSpeakPlayers = [];
                            return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) { return getNextRoundIdAfterDead(room); },
    },
    {
        id: "移交警徽",
        time: 10,
        isSkip: function (room) { return hasExposure(room); },
        selectConfig: {
            count: 1,
            selectableFilter: function (player, room) { return player.deadInfo.state == 0; },
            selectorFilter: function (player, room) { return player.leaderState == 3; },
        },
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, room];
                });
            });
        },
        onEnd: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var persons, target;
                return __generator(this, function (_a) {
                    persons = room.players.filter(function (p) { return !!p && p.leaderState == 3; });
                    target = getOneTarget(app, room, persons);
                    persons[0].leaderState = 0;
                    if (target)
                        target.leaderState = 3;
                    return [2 /*return*/, room];
                });
            });
        },
        getNextRound: function (room) { return "发表遗言"; }
    },
    {
        id: "游戏结束",
        onStart: function (app, room) {
            return __awaiter(this, void 0, void 0, function () {
                var winner, winnerCount, addXp, i, player, isWin, record, i, player, i, player, user, newPlayer, i, player, user;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            winner = getWinner(room);
                            winnerCount = room.players.filter(function (p) { return !!p && p.camp == winner; }).length;
                            addXp = 0;
                            switch (winner) {
                                case "狼人":
                                    addXp = winnerCount * 5 + 5;
                                    break;
                                case "好人":
                                    addXp = winnerCount * 2;
                                    break;
                                case "恋人":
                                    addXp = 30;
                                    break;
                            }
                            for (i = 0; i < room.players.length; i++) {
                                player = room.players[i];
                                if (!!player) {
                                    isWin = player.camp == winner;
                                    User.gameResult(app, player.user._id, player.role, isWin, addXp);
                                }
                            }
                            return [4 /*yield*/, sync(app, room)];
                        case 1:
                            room = _a.sent(); // To Remove
                            return [4 /*yield*/, pushRoomEvent(app, room, "游戏结束", { room: room, winner: winner, winnerXp: addXp })];
                        case 2:
                            _a.sent();
                            return [4 /*yield*/, GameRecord.gameOverRecord(room, winner)];
                        case 3:
                            record = _a.sent();
                            i = 0;
                            _a.label = 4;
                        case 4:
                            if (!(i < room.players.length))
                                return [3 /*break*/, 7];
                            player = room.players[i];
                            return [4 /*yield*/, User.pushMessage(app, player.user._id.toString(), "onAddGameRecord", { record: GameRecord.getRecordInfo(record, player.user._id) })];
                        case 5:
                            _a.sent();
                            _a.label = 6;
                        case 6:
                            i++;
                            return [3 /*break*/, 4];
                        case 7:
                            room.isStart = false;
                            room.deadSpeakPlayers = [];
                            room.dayRounds = [];
                            room.lastExilePlayers = [];
                            room.seatPrices = [-1];
                            while (room.seatPrices.length < room.players.length) {
                                room.seatPrices.push(100);
                            }
                            i = 0;
                            _a.label = 8;
                        case 8:
                            if (!(i < room.players.length))
                                return [3 /*break*/, 13];
                            player = room.players[i];
                            if (!player)
                                return [3 /*break*/, 12];
                            if (!!player.isOnline)
                                return [3 /*break*/, 10];
                            return [4 /*yield*/, removePlayer(room, i)];
                        case 9:
                            room = _a.sent();
                            return [3 /*break*/, 12];
                        case 10: return [4 /*yield*/, User.Model.findById(player.user._id)];
                        case 11:
                            user = _a.sent();
                            newPlayer = Player.create(user, player.isRobot, player);
                            room.players[i] = newPlayer;
                            if (isOwnerEquals(room, player.user._id)) {
                                room.owner = newPlayer.user._id;
                            }
                            _a.label = 12;
                        case 12:
                            i++;
                            return [3 /*break*/, 8];
                        case 13:
                            if (!room.isLive)
                                return [3 /*break*/, 18];
                            room.seatPrices = [];
                            i = 0;
                            _a.label = 14;
                        case 14:
                            if (!(i < room.players.length))
                                return [3 /*break*/, 18];
                            room.seatPrices.push(getSeatPrice(i, false));
                            player = room.players[i];
                            if (!player)
                                return [3 /*break*/, 17];
                            return [4 /*yield*/, User.Model.findById(player.user._id)];
                        case 15:
                            user = _a.sent();
                            if (user.isAnchor) {
                                room.seatPrices[i] = getSeatPrice(i, true);
                                return [3 /*break*/, 17];
                            }
                            room = addViewer(room, player.user._id);
                            return [4 /*yield*/, removePlayer(room, i)];
                        case 16:
                            room = _a.sent();
                            _a.label = 17;
                        case 17:
                            i++;
                            return [3 /*break*/, 14];
                        case 18:
                            room = updateOwner(room);
                            if (!!room.players.find(function (p) { return !!p && !p.isRobot; }))
                                return [3 /*break*/, 21];
                            return [4 /*yield*/, pushEvent(app, room, "onSyncRoom", {})];
                        case 19:
                            _a.sent();
                            return [4 /*yield*/, room.remove()];
                        case 20:
                            room = _a.sent();
                            return [3 /*break*/, 23];
                        case 21: return [4 /*yield*/, sync(app, room)];
                        case 22:
                            room = _a.sent();
                            _a.label = 23;
                        case 23: return [2 /*return*/, room];
                    }
                });
            });
        },
        getNextRound: function (room) { return ""; },
    },
];
function nextRound(app, room, roundId) {
    return __awaiter(this, void 0, void 0, function () {
        var round, config_1, selectablePlayers, selectorPlayers, i, selector;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    console.log("房間" + room.number + " 回合: " + room.roundId + " -> " + roundId);
                    round = rounds.find(function (r) { return r.id == roundId; });
                    if (!!round)
                        return [3 /*break*/, 2];
                    room.roundId = "";
                    return [4 /*yield*/, sync(app, room)];
                case 1:
                    room = _a.sent();
                    return [2 /*return*/];
                case 2:
                    room.players.forEach(function (p) {
                        if (!!p) {
                            p.selectablePlayers = [];
                            p.selectedPlayers = [];
                            p.isSpeaking = false;
                            p.isConfirmSkip = false;
                        }
                    });
                    room.roundId = roundId;
                    if (!(round.isSkip && round.isSkip(room)))
                        return [3 /*break*/, 3];
                    nextRound(app, room, round.getNextRound(room));
                    return [3 /*break*/, 8];
                case 3:
                    if (round.selectConfig) {
                        config_1 = round.selectConfig;
                        selectablePlayers = room.players.filter(function (p) { return !!p && config_1.selectableFilter(p, room); });
                        selectorPlayers = room.players.filter(function (p) { return !!p && config_1.selectorFilter(p, room); });
                        for (i = 0; i < selectorPlayers.length; i++) {
                            selector = selectorPlayers[i];
                            selector.selectablePlayers = selectablePlayers.map(function (p) { return p._id; });
                            while (selector.selectedPlayers.length < config_1.count) {
                                selector.selectedPlayers.push(null);
                            }
                        }
                    }
                    // room = await sync(app, room);
                    if (round.onInit && room.dayRounds.indexOf(roundId) == -1) {
                        round.onInit(app, room);
                    }
                    return [4 /*yield*/, round.onStart(app, room)];
                case 4:
                    room = _a.sent();
                    if (!round.time)
                        return [3 /*break*/, 7];
                    return [4 /*yield*/, wait(app, room, round.time)];
                case 5:
                    room = _a.sent();
                    if (!round.onEnd)
                        return [3 /*break*/, 7];
                    return [4 /*yield*/, round.onEnd(app, room)];
                case 6:
                    room = _a.sent();
                    _a.label = 7;
                case 7:
                    if (room) {
                        room.dayRounds.push(roundId);
                        nextRound(app, room, round.getNextRound(room));
                    }
                    _a.label = 8;
                case 8: return [2 /*return*/];
            }
        });
    });
}
exports.nextRound = nextRound;
/**
 * 发言规则
 * @param app
 * @param room
 * @param playerId
 * @param time
 * @param speakType  1:日常发言  2：发表遗言
 */
// export async function setPlayerSpeak(app: any, room: Document, playerId: mongodb.ObjectID , time: number, speakType: number): Promise<Document> {
// 	room.speakType = speakType;
// 	room.players.forEach(p => {
// 		if (!!p) {
// 			p.isSpeaking = p._id.equals(playerId);
// 		}
// 	});
// 	let player = room.players.find(p => !!p && p._id.equals(playerId)) as Player.Document;
// 	room = await wait(app, room, player.isRobot ? 1 : time);
// 	room.players.forEach(p => {
// 		if (!!p) {
// 			p.isSpeaking = false;
// 		}
// 	});
// 	// room = await sync(app, room);
// 	return room;
// }
function setPlayerSpeak(app, room, playerIds, playerIndex, time, speakType, isFool) {
    return __awaiter(this, void 0, void 0, function () {
        var playerId, player;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    playerId = playerIds[playerIndex];
                    if (!isFool) {
                        room.nextSpeakPlayer = playerIndex < playerIds.length - 1 ? playerIds[playerIndex + 1] : null;
                    }
                    room.speakType = speakType;
                    room.players.forEach(function (p) {
                        if (!!p) {
                            p.isSpeaking = p._id.equals(playerId);
                        }
                    });
                    player = room.players.find(function (p) { return !!p && p._id.equals(playerId); });
                    return [4 /*yield*/, wait(app, room, player.isRobot ? 1 : time)];
                case 1:
                    room = _a.sent();
                    room.players.forEach(function (p) {
                        if (!!p) {
                            p.isSpeaking = false;
                        }
                    });
                    return [2 /*return*/, room];
            }
        });
    });
}
exports.setPlayerSpeak = setPlayerSpeak;
function viewerLeave(app, room, user) {
    return __awaiter(this, void 0, void 0, function () {
        var viewerIndex;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    viewerIndex = room.viewers.findIndex(function (v) { return v.equals(user._id); });
                    if (viewerIndex == -1)
                        return [2 /*return*/, room];
                    room.viewers.splice(viewerIndex, 1);
                    return [4 /*yield*/, pushRoomEvent(app, room, "玩家离开房间", { name: User.getName(user) })];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, sync(app, room)];
                case 2:
                    room = _a.sent();
                    return [2 /*return*/, room];
            }
        });
    });
}
exports.viewerLeave = viewerLeave;
function playerLeave(app, room, user) {
    return __awaiter(this, void 0, void 0, function () {
        var playerIndex, player;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    playerIndex = room.players.findIndex(function (p) { return !!p && p.user._id.equals(user._id); });
                    if (playerIndex == -1)
                        return [2 /*return*/, room];
                    player = room.players[playerIndex];
                    if (!player)
                        return [2 /*return*/, room];
                    return [4 /*yield*/, removePlayer(room, playerIndex)];
                case 1:
                    room = _a.sent();
                    if (room.isLive) {
                        room.seatPrices[playerIndex] = getSeatPrice(playerIndex, false);
                    }
                    room = updateOwner(room);
                    if (!(!room.isLive && !room.players.find(function (p) { return !!p && !p.isRobot; })))
                        return [3 /*break*/, 4];
                    return [4 /*yield*/, room.remove()];
                case 2:
                    room = _a.sent();
                    return [4 /*yield*/, pushEvent(app, room, "onSyncRoom", {})];
                case 3:
                    _a.sent();
                    return [3 /*break*/, 7];
                case 4: return [4 /*yield*/, pushRoomEvent(app, room, "玩家离开房间", { name: User.getName(user) })];
                case 5:
                    _a.sent();
                    return [4 /*yield*/, sync(app, room)];
                case 6:
                    room = _a.sent();
                    _a.label = 7;
                case 7: return [2 /*return*/, room];
            }
        });
    });
}
exports.playerLeave = playerLeave;
function kickPlayer(app, room, pid) {
    return __awaiter(this, void 0, void 0, function () {
        var kickIndex, kickUid, i, player;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    kickIndex = -1;
                    kickUid = "";
                    i = 0;
                    _a.label = 1;
                case 1:
                    if (!(i < room.players.length))
                        return [3 /*break*/, 4];
                    player = room.players[i];
                    if (!(!!player && player._id.equals(pid)))
                        return [3 /*break*/, 3];
                    kickIndex = i;
                    kickUid = player.user._id.toString();
                    return [4 /*yield*/, removePlayer(room, i)];
                case 2:
                    room = _a.sent();
                    if (room.isLive) {
                        room.seatPrices[i] = getSeatPrice(i, false);
                    }
                    return [3 /*break*/, 4];
                case 3:
                    i++;
                    return [3 /*break*/, 1];
                case 4:
                    room = updateOwner(room);
                    if (!(kickIndex >= 0))
                        return [3 /*break*/, 9];
                    return [4 /*yield*/, sync(app, room)];
                case 5:
                    room = _a.sent();
                    return [4 /*yield*/, pushRoomEvent(app, room, "玩家被踢出房间", { playerNumber: kickIndex + 1 })];
                case 6:
                    _a.sent();
                    return [4 /*yield*/, User.pushMessage(app, kickUid, "onSyncRoom", {})];
                case 7:
                    _a.sent();
                    return [4 /*yield*/, User.pushMessage(app, kickUid, "onKickOutOfRoom", {})];
                case 8:
                    _a.sent();
                    if (room.isLive) {
                        room.seatPrices[kickIndex] = getSeatPrice(kickIndex, false);
                    }
                    _a.label = 9;
                case 9: return [2 /*return*/, room];
            }
        });
    });
}
exports.kickPlayer = kickPlayer;
function updateOwner(room) {
    var hasOwner = false;
    if (room.players.findIndex(function (p) { return !!p && isOwnerEquals(room, p.user._id); }) >= 0) {
        hasOwner = true;
    }
    else if (room.viewers.findIndex(function (v) { return isOwnerEquals(room, v); }) >= 0) {
        hasOwner = true;
    }
    if (!hasOwner) {
        if (!room.isLive) {
            var onlinePlayer = room.players.find(function (p) { return !!p && p.isOnline && !p.isRobot; });
            if (!!onlinePlayer) {
                room.owner = onlinePlayer.user._id;
            }
        }
        else {
            var firstPlayer = room.players.length > 0 ? room.players[0] : null;
            if (!!firstPlayer) {
                room.owner = firstPlayer.user._id;
            }
        }
    }
    return room;
}
exports.updateOwner = updateOwner;
function addUser(app, room, user, isRobot) {
    if (isRobot === void 0) { isRobot = false; }
    return __awaiter(this, void 0, void 0, function () {
        var player, update, firstNullIndex, i, firstSeatIndex, i;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    player = room.players.find(function (p) { return !!p && p.user._id.equals(user._id) && !p.isRobot; });
                    update = false;
                    if (!room.isLive || isRobot || user.isAnchor) {
                        firstNullIndex = room.players.findIndex(function (p) { return p == null; });
                        if (room.isLive && isRobot) {
                            firstNullIndex = -1;
                            for (i = 1; i < room.players.length; i++) {
                                if (room.players[i] == null) {
                                    firstNullIndex = i;
                                    break;
                                }
                            }
                        }
                        if (!!player) {
                            if (!player.isOnline) {
                                player.isOnline = true;
                                update = true;
                            }
                        }
                        else if (firstNullIndex >= 0) {
                            room.players[firstNullIndex] = Player.create(user, isRobot);
                            if (room.isLive && user.isAnchor) {
                                room.seatPrices[firstNullIndex] = getSeatPrice(firstNullIndex, true);
                            }
                            update = true;
                        }
                        else if (!room.viewers.find(function (v) { return v.equals(user._id); })) {
                            // 加入觀眾
                            room = addViewer(room, user._id);
                            update = true;
                        }
                        else {
                            return [2 /*return*/, new Promise(function (resolve) { return resolve(room); })];
                        }
                    }
                    else {
                        firstSeatIndex = -1;
                        for (i = 0; i < room.players.length; i++) {
                            if (!room.players[i] && room.seatPrices[i] == -1) {
                                firstSeatIndex = i;
                                break;
                            }
                        }
                        if (!!player) {
                            if (!player.isOnline) {
                                player.isOnline = true;
                                update = true;
                            }
                        }
                        else if (user.isAnchor && room.seatPrices[firstSeatIndex] == -1) {
                            room.players[firstSeatIndex] = Player.create(user, isRobot);
                            update = true;
                        }
                        else if (!room.viewers.find(function (v) { return v.equals(user._id); })) {
                            // 加入觀眾
                            room = addViewer(room, user._id);
                            update = true;
                        }
                        else {
                            //????  这句作用？
                            return [2 /*return*/, new Promise(function (resolve) { return resolve(room); })];
                        }
                    }
                    room = updateOwner(room);
                    if (!update)
                        return [3 /*break*/, 3];
                    return [4 /*yield*/, sync(app, room)];
                case 1:
                    room = _a.sent();
                    console.warn("========room.isFoolSpeaking========================         " + room.isFoolSpeaking);
                    return [4 /*yield*/, pushRoomEvent(app, room, "玩家进入房间", { userId: user._id, name: User.getName(user) })];
                case 2:
                    _a.sent();
                    _a.label = 3;
                case 3: return [2 /*return*/, new Promise(function (resolve) { return resolve(room); })];
            }
        });
    });
}
exports.addUser = addUser;
function create(mode, index, playerLimit, password, user, isLive) {
    return __awaiter(this, void 0, void 0, function () {
        var roomNumber, players, seatPrices, i, room;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (!password)
                        password = "";
                    return [4 /*yield*/, getUnusedNumber()];
                case 1:
                    roomNumber = _a.sent();
                    if (roomNumber == -1)
                        return [2 /*return*/, undefined];
                    players = [];
                    seatPrices = [-1];
                    for (i = 0; i < playerLimit; i++) {
                        players.push(null);
                        seatPrices.push(getSeatPrice(i, false));
                    }
                    return [4 /*yield*/, exports.Model.create({
                            mode: mode,
                            index: index,
                            number: roomNumber,
                            password: password,
                            players: players,
                            isLive: isLive,
                            owner: user._id,
                            seatPrices: seatPrices,
                        })];
                case 2:
                    room = _a.sent();
                    return [2 /*return*/, new Promise(function (resolve) { return resolve(room); })];
            }
        });
    });
}
exports.create = create;
;
// export async function create (mode: number, playerLimit: number, password: string, user: User.Document, players: any[] = []): Promise<Document | undefined> {
// 	if (!password) password = "";
// 	let roomNumber = await getUnusedNumber();
// 	if (roomNumber == -1) return undefined;
// 	if (players.length == 0) {
// 		for (let i = 0; i < playerLimit; i++) {
// 			players.push(null);
// 		}
// 	}
// 	let room = await Model.create({
// 		mode: mode,
// 		number: roomNumber,
// 		password: password,
// 		players: players,
// 	});
// 	return new Promise<Document>(resolve => resolve(room));
// };
/**
 * @see :  onRoomEvent  当玩家死亡  后端发给前端的数据
 * @param app
 * @param room
 * @param event   时间描述
 * @param values
 * @param playersFilter
 */
function pushRoomEvent(app, room, event, values, playersFilter) {
    if (values === void 0) { values = {}; }
    if (playersFilter === void 0) { playersFilter = null; }
    return __awaiter(this, void 0, void 0, function () {
        var err;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    values.time = Date.now();
                    return [4 /*yield*/, pushEvent(app, room, "onRoomEvent", {
                            key: event,
                            values: values,
                        }, playersFilter)];
                case 1:
                    err = _a.sent();
                    if (err)
                        console.log(err);
                    return [2 /*return*/];
            }
        });
    });
}
exports.pushRoomEvent = pushRoomEvent;
function pushEvent(app, room, route, message, playersFilter) {
    if (message === void 0) { message = {}; }
    if (playersFilter === void 0) { playersFilter = null; }
    return new Promise(function (resolve) {
        var onlinePlayers = room.players.filter(function (p) { return !!p && p.isOnline && !p.isRobot; });
        if (!!playersFilter) {
            onlinePlayers = onlinePlayers.filter(function (op) { return playersFilter(op); });
        }
        var uids = onlinePlayers.map(function (p) { return p.user._id.toString(); });
        room.viewers.forEach(function (v) { return uids.push(v.toString()); });
        if (uids.length == 0) {
            resolve("");
            return;
        }
        var statusService = app.get('statusService');
        statusService.pushByUids(uids, route, message, function (err, fails) {
            resolve(err);
        });
    });
}
exports.pushEvent = pushEvent;
function wait(app, room, time) {
    return __awaiter(this, void 0, void 0, function () {
        var _this = this;
        var promise;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, cancelWait(app, room, false)];
                case 1:
                    /**
                     * @see 等待的事件
                     * @param app
                     * @param room
                     * @param time  等待的时间
                     */
                    room = _a.sent();
                    promise = new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
                        var timeoutAt, timer, timerData;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    if (!(time == 0))
                                        return [3 /*break*/, 2];
                                    return [4 /*yield*/, sync(app, room)];
                                case 1:
                                    room = _a.sent();
                                    resolve(room);
                                    return [2 /*return*/];
                                case 2:
                                    timeoutAt = new Date();
                                    timeoutAt.setSeconds(timeoutAt.getSeconds() + time);
                                    room.timeoutAt = timeoutAt.valueOf();
                                    return [4 /*yield*/, sync(app, room)];
                                case 3:
                                    room = _a.sent();
                                    timer = setTimeout(function () {
                                        return __awaiter(this, void 0, void 0, function () {
                                            return __generator(this, function (_a) {
                                                switch (_a.label) {
                                                    case 0: return [4 /*yield*/, exports.Model.findById(room._id).exec()];
                                                    case 1:
                                                        room = _a.sent();
                                                        if (!!room) {
                                                            resolve(room);
                                                        }
                                                        return [2 /*return*/];
                                                }
                                            });
                                        });
                                    }, time * 1000);
                                    timerData = {
                                        timer: timer,
                                        resolve: resolve,
                                    };
                                    app["timeout.room." + room.number] = timerData;
                                    return [2 /*return*/];
                            }
                        });
                    }); });
                    return [2 /*return*/, promise];
            }
        });
    });
}
exports.wait = wait;
/**
 *
 * @param app
 * @param room
 * @param sync2       是否把房间数据同步到客户端     false:
 * @param isResolve
 */
function cancelWait(app, room, sync2, isResolve) {
    if (sync2 === void 0) { sync2 = true; }
    if (isResolve === void 0) { isResolve = true; }
    return __awaiter(this, void 0, void 0, function () {
        var timerData;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    timerData = app["timeout.room." + room.number];
                    if (!timerData)
                        return [3 /*break*/, 3];
                    //
                    delete app["timeout.room." + room.number];
                    clearTimeout(timerData.timer);
                    if (!(room.timeoutAt > 0))
                        return [3 /*break*/, 2];
                    room.timeoutAt = 0;
                    if (!sync2)
                        return [3 /*break*/, 2];
                    return [4 /*yield*/, sync(app, room)];
                case 1:
                    room = _a.sent();
                    _a.label = 2;
                case 2:
                    if (isResolve)
                        timerData.resolve(room);
                    _a.label = 3;
                case 3: return [2 /*return*/, new Promise(function (resolve) { return resolve(room); })];
            }
        });
    });
}
exports.cancelWait = cancelWait;
function sync(app, room) {
    return __awaiter(this, void 0, void 0, function () {
        var update, oldRoom, oldRoomObj, newRoomObj, updateRoom, updateRoomObj;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    update = JSON.parse(JSON.stringify(room));
                    delete update._syncVersion;
                    update.$inc = { _syncVersion: 1 };
                    return [4 /*yield*/, exports.Model.findByIdAndUpdate(room._id, update).exec()];
                case 1:
                    oldRoom = _a.sent();
                    room._syncVersion = oldRoom._syncVersion + 1;
                    oldRoomObj = JSON.parse(JSON.stringify(oldRoom));
                    newRoomObj = JSON.parse(JSON.stringify(room));
                    updateRoom = JsonDiff.diff(oldRoomObj, newRoomObj);
                    updateRoom._id = oldRoom._id;
                    updateRoomObj = JSON.parse(JSON.stringify(updateRoom));
                    return [4 /*yield*/, pushEvent(app, room, "onUpdateRoom", updateRoomObj)];
                case 2:
                    _a.sent();
                    return [4 /*yield*/, exports.Model.findById(room._id)];
                case 3:
                    room = _a.sent();
                    return [2 /*return*/, room];
            }
        });
    });
}
exports.sync = sync;
function initLiveRoom(room) {
    return __awaiter(this, void 0, void 0, function () {
        var i, player;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    // let newRoom = new Model();
                    // newRoom = await newRoom.save();
                    // for (let key in newRoom) {
                    // 	let skip = false;
                    // 	switch (key) {
                    // 		case "_id":
                    // 		case "isLive":
                    // 		case "isOpen":
                    // 		case "mode":
                    // 		case "number":
                    // 		case "title":
                    // 		case "coverUrl":
                    // 			skip = true;
                    // 			break;
                    // 	}
                    // 	if (skip) continue;
                    // 	room[key] = newRoom[key];
                    // }
                    // await newRoom.remove();
                    room.viewers = [];
                    room.seatPrices = [];
                    i = 0;
                    _a.label = 1;
                case 1:
                    if (!(i < room.players.length))
                        return [3 /*break*/, 5];
                    player = room.players[i];
                    if (!!!player)
                        return [3 /*break*/, 3];
                    return [4 /*yield*/, removePlayer(room, i)];
                case 2:
                    room = _a.sent();
                    _a.label = 3;
                case 3:
                    room.seatPrices.push(getSeatPrice(i, false));
                    _a.label = 4;
                case 4:
                    i++;
                    return [3 /*break*/, 1];
                case 5:
                    room.isStart = false;
                    room.owner = null;
                    // --
                    room.roundId = "";
                    return [4 /*yield*/, room.save()];
                case 6:
                    room = _a.sent();
                    return [2 /*return*/, room];
            }
        });
    });
}
exports.initLiveRoom = initLiveRoom;
function getUnusedNumber() {
    return __awaiter(this, void 0, void 0, function () {
        var times, _loop_4, state_1;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    times = 0;
                    _loop_4 = function () {
                        var minNum, maxNum, num, room;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    minNum = 1;
                                    maxNum = 999999;
                                    num = Math.floor(Math.random() * (maxNum - minNum + 1) + minNum);
                                    return [4 /*yield*/, exports.Model.findOne({ number: num }).exec()];
                                case 1:
                                    room = _a.sent();
                                    if (!room)
                                        return [2 /*return*/, { value: new Promise(function (resolve) { return resolve(num); }) }];
                                    return [2 /*return*/];
                            }
                        });
                    };
                    _a.label = 1;
                case 1:
                    if (!(times < 10))
                        return [3 /*break*/, 3];
                    return [5 /*yield**/, _loop_4()];
                case 2:
                    state_1 = _a.sent();
                    if (typeof state_1 === "object")
                        return [2 /*return*/, state_1.value];
                    return [3 /*break*/, 1];
                case 3: return [2 /*return*/, new Promise(function (resolve) { return resolve(-1); })];
            }
        });
    });
}
/**
 *
 * @param selectors
 *
 */
function getMaxSelectPlayers(selectors, room) {
    var getSelectDatas = function (players) {
        var selectCounts = {};
        players.forEach(function (player) {
            for (var i = 0; i < player.selectedPlayers.length; i++) {
                var pid2 = player.selectedPlayers[i];
                if (!pid2)
                    continue;
                var pid = pid2.toString();
                if (!selectCounts[pid])
                    selectCounts[pid] = 0;
                //标准模式警长1.5 票    传统警长2票
                !!room && room.mode == 2 ? (selectCounts[pid] += player.leaderState == 3 ? 1.5 : 1) : (selectCounts[pid] += player.leaderState == 3 ? 2 : 1);
            }
        });
        return selectCounts;
    };
    var selectCounts = getSelectDatas(selectors);
    var maxSelectCount = 0;
    for (var playerId in selectCounts) {
        if (selectCounts[playerId] > maxSelectCount)
            maxSelectCount = selectCounts[playerId];
    }
    var maxSelects = [];
    for (var playerId in selectCounts) {
        if (selectCounts[playerId] == maxSelectCount)
            maxSelects.push(new mongodb.ObjectID(playerId));
    }
    return maxSelects;
}
/**
 *
 * @param app
 * @param room
 * @param selectors    选择的对象
 * @param randomIfSame   解决票数相同的情况  true：同票随机返回一个目标  false:同票时候返回null
 *
 * @see  选择者选择的人
 *
 */
function getOneTarget(app, room, selectors, randomIfSame) {
    if (randomIfSame === void 0) { randomIfSame = true; }
    var selectTargetIds = getMaxSelectPlayers(selectors);
    if (selectTargetIds.length == 1) {
        return room.players.find(function (p) { return !!p && p._id.equals(selectTargetIds[0]); });
    }
    if (selectTargetIds.length > 1 && randomIfSame) {
        var randomOneTargetId_1 = selectTargetIds[Math.floor(Math.random() * selectTargetIds.length)];
        return room.players.find(function (p) { return !!p && p._id.equals(randomOneTargetId_1); });
    }
    return null;
}
function hasRole(room, role) {
    return !!room.players.find(function (p) { return !!p && p.role == role; });
}
function getWinner(room) {
    if (room.days >= room.players.length * 5) {
        return "法官";
    }
    var alivePlayers = room.players.filter(function (p) { return !!p && p.deadInfo.state == 0; });
    // let persons: Player.Document[] = alivePlayers.filter(p => p.camp == "好人") as Player.Document[];
    var wolfs = alivePlayers.filter(function (p) { return p.camp == "狼人"; });
    // let lovers: Player.Document[] = alivePlayers.filter(p => p.camp == "恋人") as Player.Document[];
    var normalPersons = alivePlayers.filter(function (p) { return p.camp == "好人" && p.role == "村民"; });
    var godPersons = alivePlayers.filter(function (p) { return p.camp == "好人" && p.role != "村民"; });
    var isNormalMode = room.mode == 2;
    if (isNormalMode) {
        if (godPersons.length == 0 || normalPersons.length == 0) {
            return "狼人";
        }
        else if (wolfs.length == 0) {
            return "好人";
        }
    }
    // else {
    // 	if (persons.length + lovers.length < wolfs.length) {
    // 		return "狼人";
    // 	}
    // 	else if (wolfs.length == 0 && lovers.length == 0) {
    // 		return "好人";
    // 	}
    // 	else if (wolfs.length == 0 && persons.length == 0) {
    // 		return "恋人";
    // 	}
    // }
    return "";
}
exports.getWinner = getWinner;
/**
 *
 * @see   杀死玩家  【遗言事件、改变死亡状态】
 * @param app
 * @param room
 * @param pid  被杀的那个人
 * @param type   被杀的类型     // 0: 未死, 1: 狼人殺, 2: 毒殺, 3: 鎗殺, 4: 同守同救, 5: 公投, 6: 自曝, 7：殉情【情侣】8：放逐
 * @param isFalse
 */
function killPlayer(app, room, pid, type, isFalse) {
    if (isFalse === void 0) { isFalse = false; }
    return __awaiter(this, void 0, void 0, function () {
        var playerIndex, player, targetNumbers, i, player2;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    playerIndex = room.players.findIndex(function (p) { return !!p && p._id.equals(pid); });
                    console.warn("========killPlayer=========" + pid + "====type=====" + type);
                    if (!(playerIndex >= 0))
                        return [3 /*break*/, 7];
                    player = room.players[playerIndex];
                    if (player.leaderState == 3) {
                        player.roleFlags.push("giveLeader");
                    }
                    // 0: 未死, 1: 狼人殺, 2: 毒殺, 3: 鎗殺, 4: 同守同救, 5: 公投, 6: 自曝, 7：殉情【情侣】
                    if (type == 1 || type == 2 || type == 3 || type == 4) {
                        room.deadPlayerArrEveryDay.push(playerIndex);
                        room.deadPlayerArrEveryDay.sort();
                    }
                    return [4 /*yield*/, pushRoomEvent(app, room, "玩家死亡", { number: playerIndex + 1, type: type })];
                case 1:
                    _a.sent();
                    if (type == 6) {
                    }
                    else if (room.mode == 2 && type != 6) {
                        // console.log('=====================================room.mode == 2');
                        //死亡类型枪杀      那么猎人晚上 死的话   被枪杀的人没有遗言
                        if (room.days != 1 && type == 3 && room.players.find(function (p) { return !!p && p.role == "猎人" && p.deadInfo.state != 5; })) {
                            console.warn("======第二天开始猎人晚上被杀   被枪杀的玩家没有遗言=========");
                        }
                        else {
                            room.deadSpeakPlayers.push(player._id);
                        }
                    }
                    /**
                     * 上一个死的人
                     */
                    room.lastDeadPlayer = player._id;
                    player.deadInfo = {
                        state: type,
                        day: room.days,
                        isOnline: player.isOnline,
                    };
                    if (!(!isFalse && player.isLover))
                        return [3 /*break*/, 7];
                    targetNumbers = [];
                    i = 0;
                    _a.label = 2;
                case 2:
                    if (!(i < room.players.length))
                        return [3 /*break*/, 5];
                    player2 = room.players[i];
                    if (!(!!player2 && player2.isLover))
                        return [3 /*break*/, 4];
                    return [4 /*yield*/, killPlayer(app, room, player2._id, 7, !isFalse)];
                case 3:
                    room = _a.sent();
                    targetNumbers.push(i + 1);
                    _a.label = 4;
                case 4:
                    i++;
                    return [3 /*break*/, 2];
                case 5: return [4 /*yield*/, GameRecord.addEvent(room.record, "情侣殉情", { targetNumbers: targetNumbers })];
                case 6:
                    _a.sent();
                    _a.label = 7;
                case 7: return [2 /*return*/, room];
            }
        });
    });
}
exports.killPlayer = killPlayer;
// Person.findByIdAndUpdate(_id,{$set:{name:'MDragon'}},function(err,person){
//   console.log(person.name); //MDragon
// });
// let update = JSON.parse(JSON.stringify(room));
// delete update._syncVersion;
// update.$inc = { _syncVersion: 1 };
// let oldRoom = await Model.findByIdAndUpdate(room._id, update).exec();
// return room;
// }
function relistPlayers(room, startIndex, isRight, filter) {
    if (filter === void 0) { filter = null; }
    var players = [];
    if (isRight) {
        for (var i = startIndex; i < room.players.length; i++) {
            var p = room.players[i];
            if (!!filter && !filter(p)) {
                continue;
            }
            players.push(p);
        }
        for (var i = 0; i < startIndex; i++) {
            var p = room.players[i];
            if (!!filter && !filter(p)) {
                continue;
            }
            players.push(p);
        }
    }
    else {
        for (var i = startIndex; i >= 0; i--) {
            var p = room.players[i];
            if (!!filter && !filter(p)) {
                continue;
            }
            players.push(p);
        }
        for (var i = room.players.length - 1; i > startIndex; i--) {
            var p = room.players[i];
            if (!!filter && !filter(p)) {
                continue;
            }
            players.push(p);
        }
    }
    console.log(players.length);
    return players;
}
// function getNextRoundIdBeforeDead(room: Document) {
// 	for (let i = 0; i < room.players.length; i++) {
// 		let player = room.players[i];
// 		if (!!player && player.deadInfo.state > 0 && player.deadInfo.day == room.days) {
// 			if (player.role == "猎人" && player.roleFlags.indexOf("gun") == -1 && player.deadInfo.state != 2) {
// 				return "猎人行动";
// 			}
// 			if (p.leaderState == 3 && p.roleFlags.indexOf("leader") == -1) {
// 				return "移交警徽";
// 			}
// 		}
// 	}
// 	return "发表遗言";
// }
function getNextRoundIdAfterDead(room) {
    //  警长选择发言顺序   //日常发言   //天黑
    // for (let i = 0; i < room.players.length; i++) {
    // 	let player = room.players[i];
    // 	if (!!player &&
    // 		player.deadInfo.state > 0 &&
    // 		player.deadInfo.day == room.days) {
    // 		// if (player.role == "猎人" && player.roleFlags.indexOf("gun") == -1 && dp.type != 2) {
    // 		// 	return "猎人行动";
    // 		// }
    // 		if (player.deadInfo.state != 5 &&
    // 			player.deadInfo.state != 6 &&
    // 			player.leaderState == 3) {
    // 			return "移交警徽";
    // 		}
    // 	}
    // }
    if (room.mode == 2 && !room.isMorningSpeak && room.players.find(function (p) { return !!p && p.leaderState == 3 && p.deadInfo.state == 0 && p.roleFlags.indexOf("exileFool") == -1; })) {
        return "警长选择发言顺序";
    }
    return room.isMorningSpeak ? "天黑" : "日常发言";
}
// function getNextRoundIdAfterTransfer(room:Document){
// 		//发表遗言   
// 		//room.isMorningSpeak ? "天黑" : "日常发言"
// }
/**
 *
 * @see:  可以说话的人的列表
 */
function onSpeakRoundInit(room) {
    //  取出 room中 活着的人【放逐的傻子不在里面】的 Object_id[]     /  已经轮流发言的次数初始化
    room.speakLoopTimes = 0;
    //初始化
    room.lastExilePlayers = room.players.filter(function (p) { return p.deadInfo.state == 0 && p.roleFlags.indexOf("exileFool") == -1; }).map(function (p) { return p._id; });
    return room;
}
function onSpeakRoundEnd(room) {
    /**
     * @see 发言次数更新
     */
    room.speakLoopTimes++;
    return room;
}
/**
 * @see: 将投票结果发送给前端
 * @param app
 * @param room
 * @param selectedId
 * @param type  投票类型    警长投票:1       放逐投票:2
 */
function pushVoteResult(app, room, selectedId, type) {
    return __awaiter(this, void 0, void 0, function () {
        var votes, i, i, player, selfNumber, _loop_5, j;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    votes = [[]];
                    for (i = 0; i < room.players.length; i++) {
                        votes.push([]);
                    }
                    for (i = 0; i < room.players.length; i++) {
                        player = room.players[i];
                        if (!player)
                            continue;
                        if (player.selectedPlayers.length == 0)
                            continue;
                        selfNumber = i + 1;
                        if (player.selectedPlayers.indexOf(null) >= 0) {
                            votes[0].push(selfNumber);
                            continue;
                        }
                        _loop_5 = function (j) {
                            var sp = player.selectedPlayers[j];
                            if (!sp)
                                return "continue";
                            var targetNumber = room.players.findIndex(function (p) { return !!sp && !!p && p._id.equals(sp); }) + 1;
                            votes[targetNumber].push(selfNumber);
                        };
                        for (j = 0; j < player.selectedPlayers.length; j++) {
                            _loop_5(j);
                        }
                    }
                    return [4 /*yield*/, pushRoomEvent(app, room, "投票结果", { votes: votes, playerId: selectedId, type: type })];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function isOwnerEquals(room, uid) {
    return !!room.owner && room.owner.toString() == uid.toString();
}
exports.isOwnerEquals = isOwnerEquals;
function getSeatPrice(index, isAnchor) {
    if (isAnchor)
        return -1;
    return index == 0 ? -1 : 100;
}
exports.getSeatPrice = getSeatPrice;
function removePlayer(room, index) {
    return __awaiter(this, void 0, void 0, function () {
        var player, playersCount;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    player = room.players[index];
                    if (!player)
                        return [2 /*return*/, room];
                    playersCount = room.players.length;
                    return [4 /*yield*/, player.remove()];
                case 1:
                    player = _a.sent();
                    room.players.splice(index, playersCount == room.players.length ? 1 : 0, null);
                    return [2 /*return*/, room];
            }
        });
    });
}
exports.removePlayer = removePlayer;
// export function findPlayer (room: Document, pid: mongodb.ObjectID ): Player.Document | null {
// 	for (let i = 0; i < room.players.length; i++) {
// 		let player = room.players[i];
// 		if (!player)
// 			continue;
// 		if (player._id.equals(pid))
// 			return player;
// 	}
// 	return null;
// }
// export function findPlayerByUserId (room: Document, uid: mongodb.ObjectID  ): Player.Document | null {
// 	for (let i = 0; i < room.players.length; i++) {
// 		let player = room.players[i];
// 		if (!player)
// 			continue;
// 		if (player.user._id.equals(uid))
// 			return player;
// 	}
// 	return null;
// }
function addViewer(room, uid) {
    if (!!room.viewers.find(function (uid_2) { return uid_2.equals(uid); }))
        return room;
    room.viewers.push(uid);
    return room;
}
exports.addViewer = addViewer;
// export function removeViewer (room: Document, uid: mongodb.ObjectID  ): Document {
// 	for (let i = room.viewers.length - 1; i >= 0; i--) {
// 		if (room.viewers[i].equals(uid)) {
// 			room.viewers.splice(i, 1);
// 		}
// 	}
// 	return room;
// }
/**
 *
 * @param room
 */
function hasExposure(room) {
    return !!room.players.find(function (p) { return !!p && p.deadInfo.state == 6 && p.deadInfo.day == room.days; });
}
/**
 * @see   对于多个玩家死亡顺序排序     刀杀    毒杀   枪杀
 */
function sortDeadPlayer(alivePlayers) {
    var arrays = [];
    //1：狼人刀杀
    for (var i = 0; i < alivePlayers.length; i++) {
        var player = alivePlayers[i];
        var hasKill = player.flags.indexOf("kill") >= 0;
        var hasGuard = player.flags.indexOf("guard") >= 0;
        var hasCure = player.flags.indexOf("cure") >= 0;
        if (hasKill && !hasCure && !hasGuard) {
            arrays.push(player);
        }
    }
    //毒杀
    for (var i = 0; i < alivePlayers.length; i++) {
        var player = alivePlayers[i];
        var hasPoison = player.flags.indexOf("poison") >= 0;
        if (hasPoison) {
            arrays.push(player);
        }
    }
    //4: 同守同救
    for (var i = 0; i < alivePlayers.length; i++) {
        var player = alivePlayers[i];
        var hasGuard = player.flags.indexOf("guard") >= 0;
        var hasCure = player.flags.indexOf("cure") >= 0;
        if (hasCure && hasGuard) {
            arrays.push(player);
        }
    }
    //  8   3  
    // 1 2 3 4  5 6 7 8 9 10
    //  8 3  1 2 3 4  5 6 7 8 9 10
    return uniqueArr(arrays.concat(alivePlayers));
}
// 数组去除重复
function uniqueArr(array) {
    if (!array)
        return;
    var newArr = [array[0]];
    for (var i = 0; i < array.length; i++) {
        var repeat = false; //设置重复参数
        for (var j = 0; j < newArr.length; j++) {
            if (array[i] == newArr[j]) {
                repeat = true;
                break;
            }
        }
        if (!repeat) {
            newArr.push(array[i]);
        }
    }
    return newArr;
}
// uniqueArr([8, 3 , 1 ,2 ,3, 4,  5, 6, 7, 8, 9, 10])
// Array.prototype.unique = function(){
// 	var  newArr = [this[0]];
// 	for(let i=0;i<this.length;i++){
// 			let repeat = false;//设置重复参数
// 			for(let j=0;j<newArr.length;j++){
// 				if (this[i]==newArr[j]) {
// 					repeat = true;
// 					break;
// 				}
// 			}
// 			if(!repeat){
// 				newArr.push(this[i]);
// 			}
// 	}
// 	return  newArr;
// }
// var arr = [1,2,8,9,4,5,2,4];
// console.log(arr.unique()); 
